#include "include.h"
#include "api_alg.h"
#include "ains3.h"
/*
 * 文件名称: ains3_api.c
 * 功能描述: 本文件为软件AINS3处理模块
    AT(.buf.ains3);
    AT(.rodata.ains3)
    AT(.text.ains3_proc)
    AT(.text.ains3_init)

 ****************************************************************************************
    code + rodata :11K(MODE1)    12K(MODE0)
    buf           :19K(MODE1)    27K(MODE0)
    time : 160M 下mode0:480个点处理 5.2ms (LC3) mode1:480个点处理 7.8ms (LC3)
 */
#if AINS3_EN
///默认开ains3会吃掉20ms延时（10ms凑帧,预留10ms处理）
#define FRAME_LEN		        480                       //算法处理帧长
#define PROCESS_OUT_SAMPLES     120                       //每次存取帧长
s16 ains3_pingpangcache_temp[FRAME_LEN*2] AT(.buf.ains3); //乒乓buf缓存
u8 ains3_out_buf[PROCESS_OUT_SAMPLES*2] AT(.buf.ains3);   //输出buf中转缓存
WEAK volatile u8 ains_flag = 0;                           //乒乓buf 切换标志位
uint8_t ains3_in_cnt = 0;                                 //写指针
uint8_t ains3_out_cnt = 0;                                //读指针

static ains3_cb_t ains3_cb AT(.buf.ains3);
static ains3_mic_cfg_t ains3_mic_cfg AT(.buf.ains3);

//AINS3 48k 降噪参数定义
int8_t ains3_nt                  = AINS3_PAR_NT; // -20 ~ 40
uint8_t ains3_prior_opt_idx      = AINS3_PAR_OPT;// 0 ~ 19

//AT(.com_text.ains3)
//const char ains3_info[] = "AINS3 samples = %d, isrcnt = %d (SR_%d)\n";

AT(.text.ains3_proc)WEAK
void ains3_mic_audio_input(u8 *ptr, u32 samples, int ch_mode, void *params)
{
    if (!ains3_mic_cfg.mute) {
        uint8_t process_num = samples/PROCESS_OUT_SAMPLES;
        s16 *process_pcm_ptr = (s16 *)ptr;
        if (process_num*PROCESS_OUT_SAMPLES != samples) {
            printf("ains3 input samples err\n");
            return;
        }

        while (process_num) {
            ///OUT取 PING-PONG BUFFER
            memcpy(ains3_out_buf,&ains3_pingpangcache_temp[ains3_out_cnt * PROCESS_OUT_SAMPLES],PROCESS_OUT_SAMPLES*2);
            ains3_out_cnt++;
            if(ains3_out_cnt>=FRAME_LEN*2/PROCESS_OUT_SAMPLES){
                ains3_out_cnt = 0;
            }
            ///IN存 PING-PONG BUFFER
            memcpy(&ains3_pingpangcache_temp[ains3_in_cnt * PROCESS_OUT_SAMPLES], process_pcm_ptr, PROCESS_OUT_SAMPLES * 2);
            ains3_in_cnt++;
            ///kick 低优先级线程处理
            if(ains3_in_cnt == FRAME_LEN/PROCESS_OUT_SAMPLES){
                ains_flag = 1;
                ///发射端处理kick 低现场 ，接收端处理攒够点数直接处理
                if (!wireless_role_is_adapter()) {//device
                    ains3_mic_proc_kick_start();
                }else{//adapter
                    ains3_mic_proc_cb();
                }
            }else if(ains3_in_cnt >= FRAME_LEN*2/PROCESS_OUT_SAMPLES){
                ains3_in_cnt = 0;
                ains_flag = 2;
                ///发射端处理kick 低现场 ，接收端处理攒够点数直接处理
                if (!wireless_role_is_adapter()) {//device
                    ains3_mic_proc_kick_start();
                }else{//adapter
                    ains3_mic_proc_cb();
                }
            }
            memcpy(process_pcm_ptr,ains3_out_buf,PROCESS_OUT_SAMPLES*2);
            /// break while()
            process_num--;

//                static u32 ticks = 0;
//                static u32 isr_cnt = 0;
//                isr_cnt++;
//                if (tick_check_expire(ticks,1000)) {
//                    my_printf(ains3_info, samples, isr_cnt, samples*isr_cnt);
//                    isr_cnt = 0;
//                    ticks = tick_get();
//                }
            if (ains3_mic_cfg.callback) {
                ains3_mic_cfg.callback((void *)ptr, samples, ch_mode, params);
            }
        }

    }else{

        if (ains3_mic_cfg.callback) {
            ains3_mic_cfg.callback((void *)ptr, samples, ch_mode, params);
        }
    }

}

//ains3算法启动计算 放在低优先级现场处理
AT(.text.ains3_proc)WEAK
void ains3_mic_proc_cb(void)
{
    s16 *ptr = &ains3_pingpangcache_temp[0];
    if(ains_flag == 2){
        ptr = &ains3_pingpangcache_temp[FRAME_LEN];
    }
    ains3_process(ptr);
    ains_flag = 0;
}

AT(.text.ains3_set)WEAK
void ains3_mic_output_callback_set(audio_callback_t callback)
{
    ains3_mic_cfg.callback = callback;
}


AT(.text.ains3_init)WEAK
void ains3_mic_init(u8 sample_rate, u16 samples)
{
    memset((uint8_t *)&ains3_cb, 0, sizeof(ains3_cb));
    memset((uint8_t *)&ains3_mic_cfg, 0, sizeof(ains3_mic_cfg));

    memset(ains3_pingpangcache_temp, 0, FRAME_LEN*2);

    if(ains3_nt >= 40){
        ains3_nt = 40;
    }else if(ains3_nt <= -20){
        ains3_nt = -20;
    }

    if(ains3_prior_opt_idx >=19){
        ains3_prior_opt_idx = 19;
    }

    ains3_cb.nt                = ains3_nt;
	ains3_cb.prior_opt_idx     = ains3_prior_opt_idx;//if 256fft  need choose 3
    ///以下参数用户无须修改
	ains3_cb.music_lev         = 16;
	ains3_cb.music_lev_hi      = 66;
	ains3_cb.music_lev_hi_range= 68;
	ains3_cb.ns_ps_rate        = 1;
	ains3_cb.low_fre_lev       = 7;
	ains3_cb.low_fre_range     = 1;//if 1024fft ：low_fre_range=512	; if 512fft ：low_fre_range=256	; if 256fft ：low_fre_range=128
	ains3_cb.ns_range_h        = 512;//if 1024fft ：ns_range_h=512	; if 512fft ：ns_range_h=256	; if 256fft ：low_fre_range=128
	ains3_cb.ns_range_l        = 0;//if 1024fft ：ns_range_l=1	; if 512fft ：ns_range_l=1	; if 256fft ：ns_range_l=1

	ains3_cb.noise_db          = -36;//单位db，例：小于-30db为噪声。 当nr_mode为1或2时有效
	ains3_cb.noise_db2         = -21;
	ains3_cb.noise_db3         = -26;
	ains3_cb.smooth_en         = 0;

    ains3_init(&ains3_cb);

}

AT(.text.ains3_exit)WEAK
void ains3_mic_exit(void)
{

}

AT(.text.ains3_set.param)WEAK
void ains3_mic_param_set(int8_t ains3_nt,u8 ains3_idx)
{
    if(ains3_nt >= 40){
        ains3_nt = 40;
    }else if(ains3_nt <= -20){
        ains3_nt = -20;
    }
    if(ains3_idx >=19){
        ains3_idx = 19;
    }

    ains3_cb.nt                = ains3_nt;
	ains3_cb.prior_opt_idx     = ains3_prior_opt_idx;//if 256fft  need choose 3
    ///以下参数用户无须修改
	ains3_cb.music_lev         = 16;
	ains3_cb.music_lev_hi      = 66;
	ains3_cb.music_lev_hi_range= 68;
	ains3_cb.ns_ps_rate        = 1;
	ains3_cb.low_fre_lev       = 7;
	ains3_cb.low_fre_range     = 1;//if 1024fft ：low_fre_range=512	; if 512fft ：low_fre_range=256	; if 256fft ：low_fre_range=128
	ains3_cb.ns_range_h        = 512;//if 1024fft ：ns_range_h=512	; if 512fft ：ns_range_h=256	; if 256fft ：low_fre_range=128
	ains3_cb.ns_range_l        = 0;//if 1024fft ：ns_range_l=1	; if 512fft ：ns_range_l=1	; if 256fft ：ns_range_l=1

	ains3_cb.noise_db          = -36;//单位db，例：小于-30db为噪声。 当nr_mode为1或2时有效
	ains3_cb.noise_db2         = -21;
	ains3_cb.noise_db3         = -26;
	ains3_cb.smooth_en         = 0;
    ains3_init(&ains3_cb);
}

AT(.text.ains3_set.mute)WEAK
void ains3_mic_mute_set(uint8_t mute)
{
    ains3_mic_cfg.mute = mute;
}

AT(.text.ains3_get.mute)WEAK
uint8_t ains3_mic_mute_get(void)
{
    return ains3_mic_cfg.mute;
}

#endif
